/** Fichier qui déclare un certain nombre de templates utiles.
 *
 * Ce fichier contient plusieurs templates utiles à un moment ou à un autre dans
 * le projet.
 *
 * @file ATL.hpp
 * @author Johan "Solo" Luisier
 *
 * @date 2009
 */
#ifndef ATL_H
#define ATL_H

/*******************************************************************************
 *
 * Voici la librairie des template du projet ADD, ou ADD Template Library
 *
 ******************************************************************************/

#include <iostream>
#include <functional>

#include <boost/lexical_cast.hpp>

#include "debugstreams.hpp"
#include <vector>

/** Template permettant d'écrire le contenu d'une séquence dans un flux de
 * sortie.
 *
 * Ce template permet de mettre dans un flot de sortie quelconque
 * (cout, debugstream, fichier) une variable quelconque, pour autant
 * que l'opérateur << doit définit pour ce type.
 *
 * Le template possède un pointeur sur un flot, initialisé lors de la
 * construction, et un méthode operator(), qui permet de remplir le
 * flot et de le retourner.
 *
 * @tparam T type qui est contenu dans la séquence.
 *
 * @author Johan "Solo" Luisier
 *
 * @date 2009
 *
 * @class EcrireElementConteneur "ATL.hpp" "Utils/ATL.hpp"
 */
template< typename T >
class EcrireElementConteneur : std::unary_function <T,std::ostream&>
{
public:
  /**
   * Constructeur par défaut, initialise le flot qui sera utilisé.
   *
   * @param os flot de sortie, par défaut cout.
   * @param pref préfixe, est ajouté devant chaque valeur, par défaut
   * chaîne vide.
   * @param suf suffixe, est ajouté à la fin de chaque valeur, apr
   * défaut on ajout une espace.
   */
    EcrireElementConteneur( std::ostream* os = &std::cout,
                            const std::string& pref = "",
                            const std::string& suf = " " )
        : flot( os ), prefixe( pref ), suffixe( suf )
    {};
  /**
   * Destructeur. On fait un flush, pour être sûr de tout afficher.
   */
    ~EcrireElementConteneur()
    {
        *flot << std::flush;
    };
  /**
   * Réalise l'affichage (ou le remplissage du fichier) avec la valeur
   * passée en argument.
   *
   * @param type variable qui sera écrite dans le flot.
   * @return le flot de sortie.
   */
    std::ostream& operator()(const T& type) const
    {
        return *flot << prefixe << type << suffixe;
    };
private:
  /**
   * Pointeur sur le flot utilisé.
   */
    std::ostream* flot;
  /**
   * Est ajouté devant la valeur lors de la sortie sur le flot
   */
    std::string prefixe;
  /**
   * Est ajouté derrière la valeur lors de la sortie sur le flot
   */
    std::string suffixe;
};

/** Template permettant l'extraction de la clé d'un conteneur associatif.
 *
 * Ce template permet d'extraire une clé d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @tparam Clef type de la clé du conteneur.
 * @tparam Valeur type de la valeur du conteneur.
 *
 * @author Johan "Solo" Luisier
 *
 * @date 2009
 *
 * @struct EcrireElementConteneur "ATL.hpp" "Utils/ATL.hpp"
 */
template< typename Clef, typename Valeur >
struct  ExtraireClef : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
  /**
   * Renvoie la clé d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.
   *  @return paire.first, qui est du type Clef et est la clé de
   *  l'élément du conteneur associatif.
   */
    Clef operator()( const std::pair< Clef, Valeur >& paire )
    {
        return paire . first;
    };
};

/**
 * Ce template permet d'extraire une valeur d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @author Johan "Solo" Luisier
 *
 * @date 2009
 */
template< typename Clef, typename Valeur >
struct  ExtraireValeur : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
    /**
   * Renvoie la valeur d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.
   *  @return paire.second, qui est du type Valeur et est la valeur de
   *  l'élément du conteneur associatif.
   *
   */
    Clef operator()( const std::pair< Clef, Valeur >& paire )
    {
        return paire . second;
    };
};

/**
 * Permet de lire des valeurs écrites dans une string. Utilise
 * boost::lexical_cast pour transformer la sous-chaîne de caractères
 * dans le type désiré.
 *
 * @param donnees chaîne de caractères contenant les information que
 * l'on vuet parser.
 * @param vec pointeur sur le vecteur dans lequel on veut stocker les
 * données lues.
 * @return \etrue si la conversion s'effectue sans problème, \efalse
 * sinon.
 *
 * @author Johan "Solo" Luisier
 *
 * @date 2009
 */
template< typename T >
bool lireDansVecteur(const std::string& donnees, std::vector< T > *vec)
{
    size_t taille( donnees.size() ), i(0);

    vec -> clear();

    std::string tmp;

    T type;

    for (i = 0; i < taille; i++)
    {
        while  ( donnees[i] == ' ' && i < taille )
            i++;
        tmp = "";
        while ( donnees[i] != ' ' && i < taille )
        {
            tmp += donnees[i];
            i++;
        }

        try
        {
            type = boost::lexical_cast<T>( tmp );
        }
        catch(boost::bad_lexical_cast& e)
        {
            error() << e.what() << "** " << tmp << " **" << endreq;
            return false;
        }
        vec -> push_back( type );
    }
    return true;
}

/**
 * Ce template permet d'élever un nombre quelconque à une puissance
 * entière.
 *
 * @author Johan "Solo" Luisier
 * @date Février 2012
 */
template< unsigned N, typename T >
T puissance( const T& a )
{
    if ( N == 0u ) return T( 1 );
    return N % 2 ? puissance< N / 2 >( a * a ) * a :
                   puissance< N / 2 >( a * a );
}

#endif // ATL_H
